#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>

#include "system_debug.h"

#define output(...) printf(__VA_ARGS__)
#define LOG_FILE_NAME    ("log.log")

int log_print(const char *format, ...)
{
    va_list ap;
    char buffer[1024 * 10];

    va_start(ap, format);
    int result = vsnprintf(buffer, sizeof(buffer), format, ap);
    va_end(ap);

    printf(buffer);

    FILE *file = fopen(LOG_FILE_NAME, "a+");
    fprintf(file, buffer);
    fclose(file);

    return result;
}

void print_current_time(void)
{
    struct timeval precise_time;
    gettimeofday(&precise_time, NULL);

    struct tm time;
    memcpy(&time, localtime(&precise_time.tv_sec), sizeof(struct tm));
    log_print("<%04d/%02d/%02d %02d:%02d:%02d.%03d>",
              time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
              time.tm_hour, time.tm_min, time.tm_sec, precise_time.tv_usec / 1000);
}

void hj_dbg_log_line(const char *lvl_name, const char *begin, const char *format, ...)
{
    va_list ap;
    char buffer[1024];
    char out_buffer[1024];

    va_start(ap, format);
    int result = vsnprintf(buffer, sizeof(buffer), format, ap);
    va_end(ap);

    result = result;

    struct timeval precise_time;
    gettimeofday(&precise_time, NULL);

    struct tm time;
    memcpy(&time, localtime(&precise_time.tv_sec), sizeof(struct tm));

    snprintf(out_buffer, sizeof(out_buffer), "<%04d/%02d/%02d %02d:%02d:%02d.%03d>[%s] %s\n",
             time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
             time.tm_hour, time.tm_min, time.tm_sec, precise_time.tv_usec / 1000,
             lvl_name, buffer);

    printf(out_buffer);
    FILE *file = fopen(LOG_FILE_NAME, "a+");
    fprintf(file, out_buffer);
    fclose(file);
}
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
static void debug_dump_hex(const uint8_t *ptr, int buflen, int witdh, uint8_t *buffer, int len)
{
    unsigned char *buf = (unsigned char *)ptr;
    int i, j;
    char tmp[256];
    for (i = 0; i < buflen; i += witdh)
    {
        snprintf(tmp, sizeof(tmp), "%06x: ", i);
        strcat((char *)buffer, tmp);
        for (j = 0; j < witdh; j++)
        {
            if (i + j < buflen)
            {
                snprintf(tmp, sizeof(tmp), "%02x ", buf[i + j]);
                strcat((char *)buffer, tmp);
            }
            else
            {
                snprintf(tmp, sizeof(tmp), "   ");
                strcat((char *)buffer, tmp);
            }
        }
        snprintf(tmp, sizeof(tmp), " ");
        strcat((char *)buffer, tmp);
        for (j = 0; j < witdh; j++)
        {
            if (i + j < buflen)
            {
                snprintf(tmp, sizeof(tmp), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
                strcat((char *)buffer, tmp);
            }
        }
        snprintf(tmp, sizeof(tmp), "\n");
        strcat((char *)buffer, tmp);
    }
}
void hj_dbg_log_hex(const char *lvl_name, const char *begin, const void *hex, int len, int width, const char *format, ...)
{
    va_list ap;
    char buffer[1024];
    char *out_buffer = malloc(1024 * 50);

    va_start(ap, format);
    int result = vsnprintf(buffer, sizeof(buffer), format, ap);
    va_end(ap);

    result = result;

    struct timeval precise_time;
    gettimeofday(&precise_time, NULL);

    struct tm time;
    memcpy(&time, localtime(&precise_time.tv_sec), sizeof(struct tm));

    snprintf(out_buffer, 1024 * 50, "<%04d/%02d/%02d %02d:%02d:%02d.%03d>[%s] [len:%d] %s\n",
             time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
             time.tm_hour, time.tm_min, time.tm_sec, precise_time.tv_usec / 1000,
             lvl_name, len, buffer);
    debug_dump_hex(hex, len, width, (void *)&out_buffer[strlen(out_buffer)], 1024 * 50 - strlen(out_buffer) - 1);
    out_buffer[1024 * 50 - 1] = '\0';

    printf(out_buffer);
    FILE *file = fopen(LOG_FILE_NAME, "a+");
    fprintf(file, out_buffer);
    fclose(file);
}




void assert_handler(const char *ex_string, const char *file, const char *func, int line)
{
    output("(%s) assertion failed at file:%s, function:%s, line number:%d \n", ex_string, file, func, line);
#if 1
    volatile char dummy = 0;
    while (dummy == 0);
#else
    exit(-1);
#endif
}











